﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Media;

namespace mates_viz
{

    class MatesController
    {
        UIVizualization Viz;
        stateManager stateMgr;
        soapClient client;
        UI mainWindow;

        bool loggedIn = false;
        string userName = "";

        void refreshTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        { if (loggedIn) stateMgr.Update(); }

        public MatesController(UI MainWindow)
        {
        
            // Initialize a new matescontroller and throw up the login screen.
            
            mainWindow = MainWindow;    // grab a reference to the main display
            
            Viz = new UIVizualization(mainWindow.vizCanvas, mainWindow.locKey);
            client = new soapClient();
            stateMgr = new stateManager(Viz, client);
            Viz.StateManager = stateMgr;


			Viz.userMouseOver += new UIVizualization.userMouseEventDelegate(Viz_userMouseOver);
			mainWindow.locKey.locKey_Hover_Event +=new locationKey.locKey_Hover_Delegate(LocationHover);

            mainWindow.LoginClicked += new UI.UILoginClickDelegate(mainWindow_LoginClicked);
            mainWindow.RemoveNodeClicked += new EventHandler(mainWindow_RemoveNodeClicked);
            mainWindow.AddNodeClicked += new EventHandler(mainWindow_AddNodeClicked);
            mainWindow.RemoveUserRequest += new UI.UserRequest(mainWindow_RemoveUserRequest);
            mainWindow.gpsSearchNearby+= new UI.GPSLocSearchNearby(mainWindow_gpsSearchNearby);
            mainWindow.RefreshClicked += new EventHandler(mainWindow_RefreshClicked);

            mainWindow.AddCourseRequest += new UI.UserRequest(mainWindow_AddCourseRequest);
            mainWindow.RemoveCourseRequest+=new UI.UserRequest(mainWindow_RemoveCourseRequest);
            mainWindow.AddFriendRequest += new UI.UserRequest(mainWindow_AddFriendRequest);
			mainWindow.RemoveFriendRequest += new UI.UserRequest(mainWindow_RemoveFriendRequest);
            mainWindow.AddInterestRequest += new UI.UserRequest(mainWindow_AddInterestRequest);
            mainWindow.InterestHoverOver += new UI.UserRequest(mainWindow_InterestHoverOver);
            mainWindow.InterestHoverOff += new UI.UserRequest(mainWindow_InterestHoverOff);
            mainWindow.CourseHoverOver += new UI.UserRequest(mainWindow_CourseHoverOver);
            mainWindow.CourseHoverOff += new UI.UserRequest(mainWindow_CourseHoverOff);

			mainWindow.RemoveInterestRequest += new UI.UserRequest(mainWindow_RemoveInterestRequest);
			client.MessageReceivedEvent += new soapClient.MatesMessageEvent(client_MessageReceivedEvent);
			client.MessageSentEvent += new soapClient.MatesMessageEvent(client_MessageSentEvent);

            mainWindow.locGuessDisplay.LocationSelected += new LocGuessDisplay.UILocationClickDelegate(locGuessDisplay_LocationSelected);
            mainWindow.locGPSdisplay.LocationSelected += new LocGPSdisplay.UILocationClickDelegate(locGPSdisplay_LocationSelected);
//            mainWindow.friendDisp.FriendRightClicked += new FriendDisplay.UIUserClickDelegate(friendDisplay_FriendRightClicked);
			
            mainWindow.setState(UI.state.login);


        }

        void mainWindow_InterestHoverOff(string userString)
        {
            foreach (stateManager.matesRelation rel in stateMgr.GetRelationsOfType(stateManager.matesRelationType.Interest))
            {
                if (rel.Subject == userString) { Viz.HighlightUser(rel.User, false, "HighlightUser_Interest"); }
            }
        }

        void mainWindow_InterestHoverOver(string userString)
        {
            foreach(stateManager.matesRelation rel in stateMgr.GetRelationsOfType(stateManager.matesRelationType.Interest))
            {
                if (rel.Subject == userString) { Viz.HighlightUser(rel.User, true, "HighlightUser_Interest"); }
            }
        }

        void mainWindow_CourseHoverOff(string userString)
        {
            foreach (stateManager.matesRelation rel in stateMgr.GetRelationsOfType(stateManager.matesRelationType.Course))
            {
                if (rel.Subject == userString) { Viz.HighlightUser(rel.User, false, "HighlightUser_Course"); }
            }
        }

        void mainWindow_CourseHoverOver(string userString)
        {
            foreach (stateManager.matesRelation rel in stateMgr.GetRelationsOfType(stateManager.matesRelationType.Course))
            {
                if (rel.Subject == userString) { Viz.HighlightUser(rel.User, true, "HighlightUser_Course"); }
            }
        }

		void LocationHover(int loc_id, Color loc_color, string loc_name)
		{
			int lastLocID = mainWindow.locPanel.Loc_ID;
			Viz.HighlightLoc(lastLocID, false);	// turn off highlight of last loc
			
			Viz.HighlightLoc(loc_id, true);

			stateManager.matesLoc selectedLoc = stateMgr.GetLocation(loc_id);
            string distDir = selectedLoc.Distance.ToString("0") + " ft " + soapClient.bearing((float)selectedLoc.Bearing);
            if (selectedLoc.Distance == 0) distDir = "(here)";
            
            mainWindow.locPanel.viewLoc(loc_id, loc_color, loc_name, distDir);

			stateManager.matesLoc.wallinfo locWall = selectedLoc.Wall;
			mainWindow.locPanel.UpdateWall(locWall.Text, locWall.LastUpdateTs.ToShortTimeString(), "??");
		}



		void Viz_userMouseOver(string username, int loc_id, System.Windows.Point canvasPoint)
		{
		
			stateManager.matesLoc userLoc = stateMgr.GetLocation(loc_id);
		
			List<stateManager.matesRelation> relations = stateMgr.GetRelationsWithUser(username);
			List<string> listOfRelnStrings = new List<string>();

			foreach (stateManager.matesRelation reln in relations)
			{
				string relnString = "";

				switch (reln.Type)
				{
					case stateManager.matesRelationType.Course:
						relnString = "Common course: " + reln.Subject;
						break;
					case stateManager.matesRelationType.Interest:
						relnString = "Common interest: " + reln.Subject;
						break;
					//case stateManager.matesRelationType.Friend:
					//    break;
					case stateManager.matesRelationType.FriendOfFriend:
						relnString = "Friend of " + reln.Subject;
						break;
				}

				if (relnString != "") listOfRelnStrings.Add(relnString);
			}
			
			// The user info panel is cleared and relations for this user are added

			mainWindow.PopulateUserInfoPanel(username, 
				userLoc.Name + " " +  userLoc.Distance.ToString("0") + " ft " 
				+ soapClient.bearing((float)userLoc.Bearing), ref listOfRelnStrings);
			mainWindow.MoveUserInfoBox(canvasPoint);

            mainWindow.userInfoCanv.Visibility = System.Windows.Visibility.Visible;

		}

		void mainWindow_RemoveFriendRequest(string userString)
		{
			// attempt to remove the interest through the server
			if (client.removeFriend(userString)) { mainWindow.friendDisp.RemoveFriend(userString); }
			else { mainWindow.showError("Error removing friend."); }
		}

		void client_MessageSentEvent(stateManager.message Message)
		{
			mainWindow.newMessage(Message.time, Message.from, Message.text, true);
		}

		void client_MessageReceivedEvent(stateManager.message Message)
		{
			mainWindow.newMessage(Message.time, Message.from, Message.text, false);
		}

		void mainWindow_RemoveInterestRequest(string userString)
		{
			// attempt to remove the interest through the server
			if (client.removeInterest(userString)) { mainWindow.removeInterest(userString); }
			else { mainWindow.showError("Error removing interest."); }
		}

		void mainWindow_AddCourseRequest(string userString)
		{
			// attempt to add the course through the server
            if (client.addCourse(userString)) { mainWindow.addCourse(userString); }
            else { mainWindow.showError("Error adding course."); }
		}

		void mainWindow_RemoveCourseRequest(string userString)
		{
			// attempt to remove the course through the server
			if (client.removeCourse(userString)) { mainWindow.removeCourse(userString); }
			else { mainWindow.showError("Error removing course."); }
		}

        void mainWindow_AddInterestRequest(string userString)
        {
            // attempt to add the interest through the server
            if (client.addInterest(userString))  { mainWindow.addInterest(userString); }
            else { mainWindow.showError("Error adding interest."); }
        }

        void mainWindow_AddFriendRequest(string userString)
        {
            // attempt to add the interest through the server
            if (client.addFriend(userString))
            { mainWindow.friendDisp.AddFriend(userString); }
            else { mainWindow.showError("Error adding friend."); }
        }

        void locGPSdisplay_LocationSelected(object IdentifierTag)
        {
            stateManager.matesLoc selectedLoc = (stateManager.matesLoc)IdentifierTag;

            if (!client.setLocation(selectedLoc.ID))
            {
                mainWindow.showError("Failed to set location!");
            }
            else
            {
                // Add my location to the list of locs I know about.
                stateMgr.AddLocation(selectedLoc);
                mainWindow.setState(UI.state.running);
                Viz.RotateStepCount = 1;
				stateMgr.Update();
                Viz.RotateStepCount = 10;
                loggedIn = true;
            }
           
        }

        void mainWindow_RefreshClicked(object sender, EventArgs e)
        {
            this.stateMgr.Update();
        }
//		void friendDisplay_FriendRightClicked(object IdentifierTag) { System.Windows.MessageBox.Show((string)IdentifierTag); /* Do something when a friend is R clicked */ }

        //HANDLERS:
        void mainWindow_gpsSearchNearby(string newLocX, string newLocY)
        {
            float lat, lon;
            try
            {
                lat = float.Parse(newLocX);
                lon = float.Parse(newLocY);
            }
            catch { return; }

            if (!client.getNearbyLocs(lat, lon))
            {  mainWindow.showError("Failed to acquire nearby locations!");  return;  }

            foreach (stateManager.matesLoc nearLoc in client.locsNearby)
            {   // add all of the detected locations to the list.
                mainWindow.locGPSdisplay.AddLocGPS(nearLoc.Name,
                    nearLoc.Distance, soapClient.bearing((float)nearLoc.Bearing), nearLoc);
            }
        
        }

        void mainWindow_RemoveUserRequest(string user){stateMgr.FlushUser(user);}
        void mainWindow_AddNodeClicked(object sender, EventArgs e){
			
			switch ((int)sender)
			{
				case 0:
					stateMgr.AddLocation(new stateManager.matesLoc(0, "Pierpont", 50, 10, 50, 100, "Pierpont wall."));
					stateMgr.AddUser(new stateManager.matesUser("Adam", 0));
					break;
				case 1:
					stateMgr.AddLocation(new stateManager.matesLoc(1, "MuJo", 10, 10, 10, 100, "MuJo wall."));
					stateMgr.AddUser(new stateManager.matesUser("Jeff", 1));
					break;
			}

        }
        void mainWindow_RemoveNodeClicked(object sender, EventArgs e){
			
			switch ((int)sender)
			{
				case 0:
					stateMgr.FlushUser("Adam");
					break;
				case 1:
					stateMgr.FlushUser("Jeff");
					break;
			}
	
		}
        void locGuessDisplay_LocationSelected(object Identifier){
            stateManager.matesLoc selectedLoc = (stateManager.matesLoc)Identifier;

            if (!client.setLocation(selectedLoc.ID))
            {
                mainWindow.showError("Failed to set location!");
            }
            else
            {
                // Add my location to the list of locs I know about.
                stateMgr.AddLocation(selectedLoc);
                stateMgr.SetMyLocation(userName, selectedLoc.ID);
                mainWindow.setState(UI.state.running);
                //mainWindow.FadeViz(true);   // fade viz in.
                Viz.RotateStepCount = 1;
				stateMgr.Update();
                Viz.RotateStepCount = 10;
                loggedIn = true;
            }

            //throw new Exception("The method or operation is not implemented.");
        }
        void mainWindow_LoginClicked(string user, string password){
            // this function is called when the main window receives the login credentials from the user
            if (client.doLogin(user, password)){
                // populate my settings.
                userName = user;    // keep track of currently logged-in user.
                List<string> friends = new List<string>();
                List<string> interests = new List<string>();
                List<string> courses = new List<string>();
                if (!client.getFriends(friends)) return;
                if (!client.getInterests(interests)) return;
                if (!client.getCourses(courses)) return;
                foreach (string Name in friends)
                    mainWindow.friendDisp.AddFriend(Name);
				foreach (string Name in interests)
					mainWindow.addInterest(Name);
                foreach (string Name in courses)
                    mainWindow.addCourse(Name);
                //Console.WriteLine("Getting loc guesses...");
                if (!client.getLocGuesses()) return;
                foreach (soapClient.locGuess guess in client.locGuesses){
                    stateManager.matesLoc possibleLoc = new stateManager.matesLoc(guess.loc.ID, guess.loc.Name, guess.loc.Latitude, guess.loc.Longitude, 0, 0, "No wall data.");
                    mainWindow.locGuessDisplay.AddLocGuess(guess.loc.Name, guess.score, (object)possibleLoc);
                    //Console.WriteLine("  " + guess.loc.Name + "source: " + guess.source + " score: " + guess.score.ToString("0.00"));
                }
                
                mainWindow.setState(UI.state.guess);    // move to the guess location state on the UI.

            }
            else mainWindow.showError("Error logging in.");       
        }
    }
}

